﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.DotNet.Scaffolding.Shared;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileProviders;
using Serilog;
using System.Text;
using XW.Core;
using XW.Logging;
using XW.Service;
using XW.Utils;
using XW.Web.Framework;
using XW.Web.Framework.Extensions;
using XW.Web.Framework.Jwt;
using XW.Web.Framework.Permissions;

namespace AdminWeb
{

    public class Startup
    {
        public IConfiguration Configuration { get; }
        public IWebHostEnvironment HostingEnvironment { get; }
        public Startup(IWebHostEnvironment hostingEnvironment)
        {
            Configuration = new ConfigurationBuilder()
               .SetBasePath(hostingEnvironment.ContentRootPath)
               .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
               .Build();
            Log.Logger = new LoggerConfiguration()
              .ReadFrom.Configuration(Configuration)
              .Filter.ByExcluding("SourceContext like 'Microsoft%'")
              .CreateLogger();
            HostingEnvironment = hostingEnvironment;
        }

        private const string MyAllowSpecificOrigins = "AllowSpecificOrigins";
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSqlSugar();
            services.TryAddScoped<IHttpContextAccessor, HttpContextAccessor>();
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => false;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.Configure<JwtSecurityTokenOptions>(Configuration.GetSection("IdentityOptions:JwtSecurityToken"));
            services.AddCors(options =>
            {
                options.AddPolicy(MyAllowSpecificOrigins,
                builder =>
                {
                    builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
                });
            });
            services.AddMvc(option =>
            {
                option.EnableEndpointRouting = false;
            })
           // .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
            .AddControllersAsServices()
            // json 序列化格式修改
            .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
			});
            //配置可以同步请求读取流数据
            services.Configure<KestrelServerOptions>(x =>
            {
                x.AllowSynchronousIO = true;
                x.Limits.MaxRequestBodySize = null; // 取消文件上传大小限制
            }).Configure<IISServerOptions>(x => x.AllowSynchronousIO = true);
            /* services.AddSwaggerGen(c =>
             {
                 c.SwaggerDoc("v1", new Info { Title = "App 接口文档", Version = "v1" });
                 c.IncludeXmlComments(Path.Combine(PlatformServices.Default.Application.ApplicationBasePath,
                     "Degre.Web.BGWebAPI.xml"));
                 c.DescribeAllEnumsAsStrings();
                 c.OperationFilter<HttpHeaderFilter>();
             });*/
            // Make IOptions<ExceptionalSettings> available for injection everywhere
            services.AddExceptional(Configuration.GetSection("Exceptional"), settings =>
            {
                settings.UseExceptionalPageOnThrow = HostingEnvironment.IsDevelopment();
				settings.OnBeforeLog += Settings_OnBeforeLog; 
            });
            MapsterProfile.SetConfig(services);
            // 日志
            services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
            services.AddSingleton<ILogParser, LogParser>();

            services.TryAddScoped<IPermissionService, MenuService>();
            services.AddSxAuthentication(Configuration.GetSection("IdentityOptions:Cookie"));
            services.AddCache();
            var jwtOptions = new JwtSecurityTokenOptions();
            Configuration.GetSection("IdentityOptions:JwtSecurityToken").Bind(jwtOptions);
            services.ConfigureJwtAuthentication(jwtOptions, HostingEnvironment);
        }
         
		// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
		public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider svp)
        {
             SXHttpContext.app = app;
            //if (env.IsDevelopment())
            //{
            //    app.UseExceptionHandler(builder => builder.Run(async context => await ErrorEvent(context)));

            //    // app.UseDeveloperExceptionPage();
            //}
            //else
            //{
            //    app.UseExceptionHandler("/Home/Error");
            //}
         
       
            app.UseExceptionHandling();
            app.UseJwtTokenMiddleware();
            app.UseSxAuthentication();

            // 解决 less 访问不了的问题
            var contentTypeProvide = new FileExtensionContentTypeProvider();
            if (!contentTypeProvide.Mappings.ContainsKey(".less"))
            {
                contentTypeProvide.Mappings.Add(".less", "text/less");
            }
            if (!contentTypeProvide.Mappings.ContainsKey(".json"))
            {
                contentTypeProvide.Mappings.Add(".json", "application/json");
            }
            app.UseStaticFiles( new StaticFileOptions {
                ContentTypeProvider = contentTypeProvide,
            });
            // app.MapStaticAssets();
            // 上传目录
            var uploadDirectory = Path.Combine(Directory.GetCurrentDirectory(), "upload");
            if (!Directory.Exists(uploadDirectory))
            {
                Directory.CreateDirectory(uploadDirectory);
            }
            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(uploadDirectory),
                ServeUnknownFileTypes = true,
                OnPrepareResponse = (c) =>
                { 
                    c.Context.Response.Headers.Append("Access-Control-Allow-Origin", "*");
                },
                RequestPath = "/upload"
            });
            string tempDirectory = Path.Combine(Directory.GetCurrentDirectory(), "temp");
            if (!Directory.Exists(tempDirectory))
            {
                Directory.CreateDirectory(tempDirectory);
            }
            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(tempDirectory),
                OnPrepareResponse = (c) =>
                {
                    c.Context.Response.Headers.Append("Access-Control-Allow-Origin", "*"); 
                },
                RequestPath = "/temp"
            });
            //app.UseExceptional();
            app.UseCors(MyAllowSpecificOrigins);

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
                routes.MapRoute(
                  name: "areasDefault",
                  template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
                );
            });
            /*  app.UseSwagger();
              app.UseSwaggerUI(c =>
              {
                  c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
              });*/
            //app.UseExceptional();
        }
        private void Settings_OnBeforeLog(object? sender, StackExchange.Exceptional.ErrorBeforeLogEventArgs e)
        {
            if (e.Error.CustomData == null)
            {
                e.Error.CustomData = new Dictionary<string, string>();
            }
            // 错误内容
            e.Error.AddBody();
            // 获取用户Id
            e.Error.AddUserId();

        }
        public Task ErrorEvent(HttpContext context)
        {
            var feature = context.Features.Get<IExceptionHandlerFeature>();
            var error = feature?.Error;
            Log.Error(error, "{0}{1}", error?.Message, error?.StackTrace);
            return context.Response.WriteAsync(JsonHelper.ToJson(new { resultCode = ResultCode.Error, message = "系统未知异常，请联系管理员" }), Encoding.UTF8);
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        //public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        //{
        //    if (env.IsDevelopment())
        //    {
        //        app.UseDeveloperExceptionPage();
        //    }

        //    app.UseRouting();

        //    app.UseEndpoints(endpoints =>
        //    {
        //        endpoints.MapGet("/", async context =>
        //        {
        //            await context.Response.WriteAsync("Hello World!");
        //        });
        //    });
        //}
    }
}
